#ifndef G1_REGION_HPP
#define G1_REGION_HPP



#include <cstddef>
#include <vector>
#include <set>
#include "g1_object.hpp"

class G1Region
{
public:
    static const size_t REGION_SIZE = 1024 * 1024; // 1MB 的Region大小
    
private:
    void *start_addr;                              // Region的起始地址
    size_t used_size;                              // Region中已使用的内存大小
    bool is_empty;                                 // Region是否为空
    bool is_humongous;                             // Region是否为大对象
    int gc_epoch;                                  // Region的GC标记
    struct ObjectEntry
    {
        void* addr;
        size_t size;
    };

    std::vector<ObjectEntry> objects; // 存储Region中所有对象的地址和大小
    std::set<void*> live_objects; // 当前GC周期中的存活对象
    
public:
    G1Region(void *addr) : start_addr(addr), used_size(0), is_empty(true), is_humongous(false), gc_epoch(0) {}

    bool is_full() const { return used_size >= REGION_SIZE; }
    size_t free_size() const { return REGION_SIZE - used_size; }
    void mark_as_empty(){
        is_empty=true;
        used_size=0;
        objects.clear();
        live_objects.clear();
    }
    void set_is_humongous(bool humongous){is_humongous=humongous;}
    bool get_is_humongous(){return is_humongous;}
    static constexpr size_t get_region_size() { return REGION_SIZE; }
    void record_allocation(void *addr, size_t size)
    {
        objects.push_back({addr, size});
    }

    void* allocate(size_t size)
    {
        if(used_size+size>REGION_SIZE)
        {
            return nullptr;
        }

        void* addr=static_cast<char*>(start_addr)+used_size;
        used_size+=size;
        is_empty=false;
        record_allocation(addr,size);
        return addr;
    }

    bool has_live_objects(int current_epoch)
    {
        for(auto& entry:objects){
            G1Object* obj=G1Object::from_address(entry.addr);
            if(obj->is_marked_in_epoch(current_epoch)){
                return true;
            }
        }
        return false;
    }

    bool is_empty_region()
    {
        return is_empty;
    }
};
#endif